package com.hfi.ood.litejunit.v3.framework.runners;

import com.hfi.ood.litejunit.v3.framework.annotation.Test;
import com.hfi.ood.litejunit.v3.framework.notification.RunNotifier;
import com.hfi.ood.litejunit.v3.framework.runner.Description;
import com.hfi.ood.litejunit.v3.framework.runner.Runner;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author ChangLiang
 * @date 2020/5/27
 */
public class TestClassMethodsRunner extends Runner {

    private final List<Method> testMethods;

    private final Class<?> testClass;

    public TestClassMethodsRunner(Class<?> klass) {
        testClass= klass;
        this.testMethods= new TestIntrospector(testClass).getTestMethods(Test.class);
    }

    protected String getName() {
        return getTestClass().getName();
    }

    protected String testName(Method method) {
        return method.getName();
    }

    protected Description methodDescription(Method method) {
        return Description.createTestDescription(getTestClass(), testName(method));
    }

    @Override
    public Description getDescription() {
        Description spec = Description.createSuiteDescription(getName());
        testMethods.forEach(method->spec.addChild(methodDescription(method)));
        return spec;
    }

    private Object createTest() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        return getTestClass().getConstructor().newInstance();
    }

    private void invokeTestMethod(Method method, RunNotifier notifier) {
        Object test;
        try {
            test = createTest();
        } catch (Exception e) {
            return;
        }
        createMethodRunner(test,method,notifier).run();
    }

    private TestMethodRunner createMethodRunner(Object test, Method method, RunNotifier notifier) {
        return new TestMethodRunner(test, method, notifier, methodDescription(method));
    }


    @Override
    public void run(RunNotifier notifier) {
        for (Method method : testMethods) {
            invokeTestMethod(method,notifier);
        }
    }

    protected Class<?> getTestClass() {
        return testClass;
    }
}
